package com.fzu.geometa.metadata.mapper.handler;


import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKBReader;
import com.vividsolutions.jts.io.WKTWriter;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;

@MappedTypes(Polygon.class)
@MappedJdbcTypes(JdbcType.OTHER)
public class PolygonTypeHandler extends BaseTypeHandler<Polygon> {

    // mySQL  geometry 类型的存储方式为
    // sird(4 byte) + wkb
    private final static int WKB_OFFSET = 4;
    /**
     * 返回一个 Polygon
     * @param mySQlBytes mySQL 的 Polygon 字节存储
     * @return
     */
    private Polygon getPolygon(byte[] mySQlBytes) {
        WKBReader wkbReader = new WKBReader();
        Geometry geometry;
        // 解析 wkb
        try {
            geometry = wkbReader.read(Arrays.copyOfRange(mySQlBytes, WKB_OFFSET, mySQlBytes.length));
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
        // 解析坐标系

        int srid = ByteBuffer
                .wrap(Arrays.copyOfRange(mySQlBytes, 0, WKB_OFFSET))
                .order(ByteOrder.LITTLE_ENDIAN)        // 小端法
                .getInt();
        geometry.setSRID(srid);
        return (Polygon) geometry;
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Polygon parameter, JdbcType jdbcType) throws SQLException {
        WKTWriter wktWriter = new WKTWriter();
        String wkt = wktWriter.write(parameter);
        ps.setString(i,wkt);
    }

    @Override
    public Polygon getNullableResult(ResultSet rs, String columnName) throws SQLException {
        byte[] bytes = rs.getBytes(columnName);
        return getPolygon(bytes);
    }

    @Override
    public Polygon getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        byte[] bytes = rs.getBytes(columnIndex);
        return getPolygon(bytes);
    }

    @Override
    public Polygon getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        byte[] bytes = cs.getBytes(columnIndex);
        return getPolygon(bytes);
    }
}
